//==========================================================================
// Copyright (c) 2000-2006,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include "ssp.h"
#include <util.h>
#include "lcd_monahans.h"

#define CONFIG_PXA3xx
static struct ssp_dev ssp2;


#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

void pxa3xx_enable_ssp2_pins(void)
{
	pxa3xx_mfp_set_configs(littleton_ssp2_pins, ARRAY_SIZE(littleton_ssp2_pins));
}
void pxa3xx_enable_ssp3_pins(void)
{
	pxa3xx_mfp_set_configs(littleton_ssp3_pins,
			ARRAY_SIZE(littleton_ssp3_pins));
}

void pxa3xx_enable_lcd_pins(void)
{
       pxa3xx_mfp_set_configs(littleton_lcd_pins, ARRAY_SIZE(littleton_lcd_pins));
 }

void lcd_ssp_init(void)
{
	pxa3xx_enable_ssp2_pins();
	pxa_set_cken(CKEN_SSP2, 1);
	/* grab the port, configure it, then enable it */
	ssp_init(&ssp2, 2, 0);
	ssp_disable(&ssp2);
	ssp_config(&ssp2, 0x0, 0x18, 0x0, 0x001fff81);
	ssp_enable(&ssp2);
	#if 0
	printf(" SSCR0_P(dev->port) = 0x%x \n", SSCR0_P(ssp2.port) );
	printf(" SSCR1_P(dev->port) = 0x%x \n", SSCR1_P(ssp2.port) );
	printf(" SSSR_P(dev->port) = 0x%x \n", SSSR_P(ssp2.port) );
	printf(" SSITR_P(dev->port) = 0x%x \n", SSITR_P(ssp2.port) );
	printf(" SSDR_P(dev->port) = 0x%x \n", SSDR_P(ssp2.port) );
	printf(" SSTO_P(dev->port) = 0x%x \n", SSTO_P(ssp2.port) );
	printf(" SSPSP_P(dev->port) = 0x%x \n", SSPSP_P(ssp2.port) );
	printf(" SSTSA_P(dev->port) = 0x%x \n", SSTSA_P(ssp2.port) );
	printf(" SSRSA_P(dev->port) = 0x%x \n", SSRSA_P(ssp2.port) );
	printf(" SSTSS_P(dev->port) = 0x%x \n", SSTSS_P(ssp2.port) );
	printf(" SSACD_P(dev->port) = 0x%x \n", SSACD_P(ssp2.port) );
	printf(" SSACDD_P(dev->port) = 0x%x \n", SSACDD_P(ssp2.port) );
	#endif
	ssp_flush(&ssp2);

}
/* TODO: One might want to consider abstracting all these ssp_command
 *       functions into a single function.
 *	 Change the Magic number to MACRO.
 */

static void ssp_command(struct ssp_dev *dev, u32 data)
{
	u32 command = 0;

	ssp_disable(dev);
	ssp_config(dev, 0x0, 0x18, 0x0, 0x001fff81);

	command = data << 9;
	ssp_write_word(dev, command);
	ssp_flush(dev);
}
static void ssp_command_one(struct ssp_dev *dev, u32 data, u32 param)
{
	u32 command = 0;

	ssp_disable(dev);
	ssp_config(dev, 0x0, 0x18, 0x0, 0x001fff81);

	command = data << 9;
	command |= 0x100;
	command |= param;

	ssp_write_word(dev, command);
	ssp_flush(dev);
}
void lcd_panel_reset(void)
{
	/* start chucking commands at the lcd */
	ssp_command(&ssp2, 0x1); // reset
	ssp_command(&ssp2, 0x0); // nop
	ssp_command(&ssp2, 0x0); // nop
	ssp_command(&ssp2, 0x0); // nop
}

/*****************************/
/* QVGA pass-through display */
/* D4 D3 D1 D0               */
/*  0  0  0  1               */
/*****************************/
void qvga_pass_through_mode(void)
{
//rintf( "qvga_pass_through_mode\n");
	ssp_command_one(&ssp2, 0xB0, 0x16);
	ssp_command_one(&ssp2, 0xBC, 0x81);
	ssp_command_one(&ssp2, 0xE1, 0x00);

	if (1)	/* Littleton Rev 1.x */
		ssp_command_one(&ssp2, 0x36, 0x50);
	else	/* Littleton Rev 4.x */
		ssp_command_one(&ssp2, 0x36, 0x00);

	ssp_command_one(&ssp2, 0x3B, 0x22);
}

/*************************************/
/* QVGA RAM display + QVGA RAM write */
/* D4 D3 D1 D0                       */
/*  0  1  1  0                       */
/*************************************/
void qvga_ram_write_mode(void)
{
//	printf( "qvga_ram_write_mode\n");
	ssp_command_one(&ssp2, 0xB0, 0x17);
	ssp_command_one(&ssp2, 0xBC, 0xAA);
	ssp_command_one(&ssp2, 0x36, 0xC0);
	ssp_command_one(&ssp2, 0x3B, 0x22);
	ssp_command_one(&ssp2, 0xE1, 0x01);
}
static void ssp_command_two(struct ssp_dev *dev,
		u32 data, u32 param_one, u32 param_two)
{
	u32 command = 0;

	/*
	 * Note the least signficant nible is 'a' here,
	 * not '1' as in previous functions. We're now sending 27 bits!!
	 */
	ssp_disable(dev);
	ssp_config(dev, 0x0, 0x18, 0x0, 0x001fff8a);

	command = data << 18;
	command |= 0x20000;
	command |= (param_one << 9);
	command |= 0x100;
	command |= param_two;

	ssp_write_word(dev, command);
	ssp_flush(dev);
}

void lcd_panel_config(void)
{
	ssp_command_two(&ssp2, 0xb8, 0xff, 0xf9); // Output control
	ssp_command(&ssp2, 0x11); // sleep out
	ssp_command_one(&ssp2, 0xba, 0x01); // Display mode (1)
	ssp_command_one(&ssp2, 0xbb, 0x00); // Display mode (2)
	ssp_command_one(&ssp2, 0x3a, 0x60); // Display mode 18-bit RGB
	ssp_command_one(&ssp2, 0xbf, 0x10); // Drive system change control
	ssp_command_one(&ssp2, 0xb1, 0x56); // Booster operation setup
	ssp_command_one(&ssp2, 0xb2, 0x33); // Booster mode setup
	ssp_command_one(&ssp2, 0xb3, 0x11); // Booster frequency setup
	ssp_command_one(&ssp2, 0xb4, 0x02); // Op amp/system clock
	ssp_command_one(&ssp2, 0xb5, 0x35); // VCS voltage
	ssp_command_one(&ssp2, 0xb6, 0x40); // VCOM voltage
	ssp_command_one(&ssp2, 0xb7, 0x03); // External display signal
	ssp_command_one(&ssp2, 0xbd, 0x00); // ASW slew rate
	ssp_command_one(&ssp2, 0xbe, 0x00); // Dummy data for QuadData operation
	ssp_command_one(&ssp2, 0xc0, 0x11); // Sleep out FR count (A)
	ssp_command_one(&ssp2, 0xc1, 0x11); // Sleep out FR count (B)
	ssp_command_one(&ssp2, 0xc2, 0x11); // Sleep out FR count (C)
	ssp_command_two(&ssp2, 0xc3, 0x20, 0x40); // Sleep out FR count (D)
	ssp_command_two(&ssp2, 0xc4, 0x60, 0xc0); // Sleep out FR count (E)
	ssp_command_two(&ssp2, 0xc5, 0x10, 0x20); // Sleep out FR count (F)
	ssp_command_one(&ssp2, 0xc6, 0xc0); // Sleep out FR count (G)
	ssp_command_two(&ssp2, 0xc7, 0x33, 0x43); // Gamma 1 fine tuning (1)
	ssp_command_one(&ssp2, 0xc8, 0x44); // Gamma 1 fine tuning (2)
	ssp_command_one(&ssp2, 0xc9, 0x33); // Gamma 1 inclination adjustment
	ssp_command_one(&ssp2, 0xca, 0x00); // Gamma 1 blue offset adjustment
	ssp_command_two(&ssp2, 0xec, 0x01, 0xf0); // Horizontal clock cycles
}
void qvga_transfer_config(void)
{
//	printf("qvga_transfer_config()\n");
	ssp_command_one(&ssp2, 0xd6, 0x02); // Blanking period control (1)
	ssp_command_two(&ssp2, 0xd7, 0x08, 0x04); // Blanking period control (2)
	ssp_command_one(&ssp2, 0xd8, 0x01); // CKV timing control on/off
	ssp_command_two(&ssp2, 0xd9, 0x00, 0x08); // CKV 1,2 timing control
	ssp_command_two(&ssp2, 0xde, 0x05, 0x0a); // OEV timing control
	ssp_command_two(&ssp2, 0xdf, 0x0a, 0x19); // ASW timing control (1)
	ssp_command_one(&ssp2, 0xe0, 0x0a); // ASW timing control (2)

	ssp_command(&ssp2, 0x21); // Invert for normally black display
	ssp_command(&ssp2, 0x29); // Display on
}
void qvga_osc_config(void)
{
//	printf("qvga_osc_config()\n");
	ssp_command_one(&ssp2, 0xe0, 0x0A);
	ssp_command_one(&ssp2, 0xe2, 0x00);
	ssp_command_one(&ssp2, 0xe3, 0x32);
	ssp_command_two(&ssp2, 0xe4, 0x00, 0x03);
	ssp_command_two(&ssp2, 0xe5, 0x02, 0x04);
	ssp_command_one(&ssp2, 0xe6, 0x03);
	ssp_command_two(&ssp2, 0xe7, 0x04, 0x0A);
	ssp_command_one(&ssp2, 0xe8, 0x04);
	ssp_command_one(&ssp2, 0xe9, 0x10);
	ssp_command_two(&ssp2, 0xea, 0x20, 0x00);

	ssp_command(&ssp2, 0x21); // Invert for normally black display
	ssp_command(&ssp2, 0x29); // Display on
}

static void configure_littleton_lcd(void)
{
//	printf("Configuring Littleton LCD panel...\n");

	lcd_ssp_init();
	lcd_panel_reset();
	#if 0//CONFIG_LITTLETON_SMART_PANEL
		qvga_ram_write_mode();
	#else
		qvga_pass_through_mode();
	#endif
	lcd_panel_config();
	#if 0//CONFIG_LITTLETON_SMART_PANEL
		qvga_osc_config();
	#else
		qvga_transfer_config();
	#endif
}
#if 0
static void littleton_lcd_power(int on)
{
	if(on){
		/* Turn LCD ON */
		ssp_command(&ssp2, 0x29); /* Display ON */
		ssp_command_two(&ssp2, 0xB8, 0xFF, 0xF9); /* Output Control */
		ssp_command(&ssp2, 0x11); /* Sleep out */
		ssp_command_one(&ssp2, 0xB0, 0x16); /* Wake */
		configure_littleton_lcd();
	} else {
		/* Turn LCD OFF */
		ssp_command_one(&ssp2, 0x28, 0x00); /* Display off */
		ssp_command_two(&ssp2, 0xB8, 0x80, 0x02); /* Output control */
		ssp_command_one(&ssp2, 0x10, 0x00); /* Sleep in */
		ssp_command_one(&ssp2, 0xB0, 0x00); /* Deep stand by in */
	}
	return;
}
#endif

void Lcm_DisplayOn()
{
 //   init();
  	pxa3xx_enable_lcd_pins();
	configure_littleton_lcd();
//	littleton_lcd_power(1);
}

void BackLight_Open()
{
//	XllpGpioSetDirection(((P_XLLP_GPIO_T)0x40E00000), 14, 1);
//	XllpGpioSetOutputLevel(((P_XLLP_GPIO_T)0x40E00000),14, 1);
}

